package com.bkhech.controller;


import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.bkhech.RedisKeyConstant;
import com.bkhech.excptions.GraceException;
import com.bkhech.grace.result.GraceJSONResult;
import com.bkhech.grace.result.ResponseStatusEnum;
import com.bkhech.pojo.netty.NettyServerNode;
import com.bkhech.service.ChatMessageService;
import com.bkhech.utils.PagedGridResult;
import com.bkhech.utils.RedisOperator;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.nio.charset.StandardCharsets;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import static com.bkhech.ZkConstant.NODE_NAME;

@RestController
@RequestMapping("/chat")
@Slf4j
public class ChatController {
    @Resource
    private RedisOperator redis;

    @Resource
    private ChatMessageService chatMessageService;

    @Resource(name = "curatorClient")
    private CuratorFramework zkClient;


    /**
     * 获取未读数量，获取时机：在好友列表聊天页
     * @param myId
     * @return
     */
    @PostMapping("/getMyUnReadCounts")
    public GraceJSONResult getMyUnReadCounts(String myId) {
        String key = String.join(StrUtil.COLON, RedisKeyConstant.CHAT_MSG_LIST, myId);
        Map<Object, Object> hgetall = redis.hgetall(key);
        return GraceJSONResult.ok(hgetall);
    }

    /**
     * 清除未读数量，清除时机：进入聊天对话框，则清除所有未读标志
     * @param myId
     * @param oppositeId
     * @return
     */
    @PostMapping("/clearMyUnReadCounts")
    public GraceJSONResult clearMyUnReadCounts(String myId, String oppositeId) {
        String key = String.join(StrUtil.COLON, RedisKeyConstant.CHAT_MSG_LIST, myId);
        redis.setHashValue(key, oppositeId, "0");
        return GraceJSONResult.ok();
    }

    @PostMapping("/list/{senderId}/{receiverId}")
    public GraceJSONResult list(@PathVariable("senderId") String senderId, @PathVariable("receiverId") String receiverId,
                                Integer page, Integer pageSize) {
        if (StrUtil.isBlank(senderId) || StrUtil.isBlank(receiverId)) {
            GraceException.display(ResponseStatusEnum.SYSTEM_ERROR_NOT_BLANK);
        }
        if (page == null || page == 0) {
            page = 1;
        }
        if (pageSize == null || pageSize == 0) {
            page = 20;
        }
        PagedGridResult pagedGridResult = chatMessageService.queryChatMsgList(senderId, receiverId, page, pageSize);
        return GraceJSONResult.ok(pagedGridResult);
    }

    @PostMapping("/signRead/{msgId}")
    public GraceJSONResult signRead(@PathVariable("msgId") String msgId) {
        if (StrUtil.isBlank(msgId)) {
            GraceException.display(ResponseStatusEnum.SYSTEM_ERROR_NOT_BLANK);
        }
        chatMessageService.updateMsgSignRead(msgId);
        return GraceJSONResult.ok();
    }

    /**
     * 获取最小连接数的 Netty 服务器
     *  基于客户端的负载均衡策略（客户端是当前 Controller，服务端是 zookeeper），和 spring cloud 的负载均衡策略是一致的，都是基于户端的负载均衡策略。
     *  像 Nginx 是基于服务端的负载均衡策略
     * @return
     */
    @PostMapping("/getNettyOnlineInfo")
    public GraceJSONResult getNettyOnlineInfo() {
        final String parentPath = NODE_NAME;
        try {
            // 从 zk 中获得当前已经注册的 netty 服务列表
            List<String> nodeList = zkClient.getChildren().forPath(parentPath);
            log.info(parentPath + " 下的子节点长度为：{}, 子节点都是：{}", nodeList.size(), JSONUtil.toJsonStr(nodeList));
            NettyServerNode minNettyServerNode = new NettyServerNode();
            if (!CollectionUtils.isEmpty(nodeList)) {

                minNettyServerNode = nodeList.stream().map(node -> {
                            byte[] bytes;
                            try {
                                bytes = zkClient.getData().forPath(parentPath + StrUtil.SLASH + node);
                            } catch (Exception e) {
                                throw new RuntimeException(e);
                            }
                            String nodeJson = StrUtil.str(bytes, StandardCharsets.UTF_8);
                            log.info("nodeJson：{}", nodeJson);
                            return JSONUtil.toBean(nodeJson, NettyServerNode.class);
                        })
                        // 获取当前所有 zk 服务器中，连接数最少的服务器，获得 ip，port 返回给前端
                        .min(Comparator.comparing(NettyServerNode::getOnlineCounts)).get();
            }
            return GraceJSONResult.ok(minNettyServerNode);
        } catch (Exception e) {
            log.error("获取子节点失败：{}, {}", e, e.getMessage());
            throw new RuntimeException(e);
        }
    }


}

